package com.lipaluma.field.adaptor.impl;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.lang.ArrayUtils;

import com.lipaluma.annotations.adaptors.standard.StringReplace;
import com.lipaluma.annotations.adaptors.standard.StringReplaces;
import com.lipaluma.context.Context;
import com.lipaluma.exceptions.CsvParserException;
import com.lipaluma.field.adaptor.Adaptor;
import com.lipaluma.xml.adaptor.XmlAdaptor;
import com.lipaluma.xml.adaptor.XmlStringReplaceAdaptor;

/**
 * Adaptor StringReplace replaces substring in the entry value with replacement
 * <p>
 * To initialize StringReplace Adaptor : 
 * <ul>
 * <li>With annotation : add {@link StringReplace} annotation to the field. To do several replacements, use {@link StringReplaces}</li>
 * <li>on xml file : add one or more element <code>&lt;stringReplace toFind="substring" replacement="value"/></code> in <code>&lt;column></code> element</li>
 * </ul>
 * 
 * @author Mario
 */
public class StringReplaceAdaptor implements Adaptor {

	private List<Replace> listReplaces = new ArrayList<StringReplaceAdaptor.Replace>();

	public StringReplaceAdaptor() {}
	/**
	 * Create a StringReplaceAdaptor intended to replace all 'toFind' strings by the 'replacement' strings.
	 * @param toFind substring to replace
	 * @param replacement the replacement
	 */
	public StringReplaceAdaptor(String toFind, String replacement) {
		listReplaces.add(new Replace(toFind, replacement));
	}
	/**
	 * Create a StringReplaceAdaptor intended to replace all 'toFinds' strings with the respective 'replacements' strings at the index on the array.
	 * @param toFind substring to replace
	 * @param replacement the replacement
	 */
	public StringReplaceAdaptor(String[] toFinds, String[] replacements) {
		if(ArrayUtils.isEmpty(toFinds) || ArrayUtils.isEmpty(replacements))
			throw new CsvParserException("the parameters must be initialized and not empty");
		if(toFinds.length != replacements.length)
			throw new CsvParserException("The length of parameters arrays must be equals");
		for (int i = 0; i < replacements.length; i++) {
			listReplaces.add(new Replace(toFinds[i], replacements[i]));			
		}
	}
	
	@Override
	public boolean init(Context context, Field field) {
		StringReplaces replaces = field.getAnnotation(StringReplaces.class);
		if(replaces != null) {
			for (StringReplace replace : replaces.value()) {
				this.listReplaces.add(new Replace(replace.pattern(), replace.replace()));
			}
			return true;
		}
		StringReplace replace = field.getAnnotation(StringReplace.class);
		if(replace != null) {
			this.listReplaces.add(new Replace(replace.pattern(), replace.replace()));
			return true;
		}
		return false;
	}
	
	@Override
	public boolean init(Context context, Field field, XmlAdaptor xml) {
		XmlStringReplaceAdaptor xmlAdaptor = (XmlStringReplaceAdaptor)xml;
		this.listReplaces.add(new Replace(xmlAdaptor.getFind(), xmlAdaptor.getReplace()));
		return true;
	}
	
	public String adapt(String value) {
		for(Replace replace : this.listReplaces) {
			value = replace.toFind.matcher(value).replaceAll(replace.replacement);
		}
		return value;
	}

	private class Replace {
		public Pattern toFind;
		public String replacement;
		public Replace(String toFind, String replacement) {
			this.toFind = Pattern.compile(toFind);
			this.replacement = replacement;
		}
	}
}
